Control Input Field with buttons

With ReactJS, I wanted to create an number input field that can both be edited by keyboard input and incremental buttons like

Most tutorials do not utilize the useRef hook which I think helps simply and easily expand logic.

import {useState, useEffect, useRef} from 'react'

import { TiArrowLoop } from 'react-icons/ti'
import { FaForward } from 'react-icons/fa'
import { IoIosTimer } from 'react-icons/io'

import { StyledPlayerSettings } from 'styles/PlayerSettings.styled'
import { GiMetronome } from 'react-icons/gi'
import { ToggleSwitch } from './ToggleSwitch'
import next from 'next'


export const Metronome = ({settings}) => {

  const inputSpeedRef = useRef(null);

  const [timerSpeed, setTimerSpeed] = useState(settings.advSpeed)
  const [metronomeToggle, setMetronomeToggle] = useState(false)
  const [counter, setCounter] = useState(0)
  const [activeSlides, setactiveSlides]     = useState([
    {id: 1, title: 'slide one', color: '#8dc3bf'},
    {id: 2, title: 'slide two', color: '#7aa19e'}, 
    {id: 3, title: 'slide three', color: '#4c6261'}
  ]);


  async function updateAdvSpeed(speed){
    const min = 1
    const max = 100
    const value = Math.max(min, Math.min(max, speed));
    setTimerSpeed(value)
    
    // set_database
  }


  useEffect(() => {

    const timer = setInterval(() => { 
      setCounter(count => {

          setMetronomeToggle( prev => !prev);
          if (count === activeSlides.length)  return 1
          return count += 1;
      });
    }, 1 * 1000);

    return () => {              
        clearInterval(timer);  
    };  
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])
  


  return (

    <StyledPlayerSettings>
      <h2>Player Settings</h2>
      <label htmlFor="">change and preview slide advance tempo</label>

      {settings && 

        <article className='settings'>


            <div className="form-item timer">
              <IoIosTimer className='iconTimer'/>

              <input 
                ref={inputSpeedRef}
                type="number" 
                // defaultValue={settingsState[0].advSpeed}
                value={timerSpeed}
                min='1'
                max='100'
                
                onChange={(e) => updateAdvSpeed(e.target.value)}
              />

              <span 
                className='input-button add'  
                onClick={e => updateAdvSpeed(Number(inputSpeedRef.current.value) + 1)}   
              > + 
              </span>
              <span 
                className='input-button remove' 
                onClick={e => updateAdvSpeed(Number(inputSpeedRef.current.value) + -1)}   
              > - 
              </span>
            </div>
            <div className="preview">
              {metronomeToggle && (
                  <div className="metronome">
                    <GiMetronome />
                  </div>
                )}
                {!metronomeToggle && (
                  <div className="metronome">
                    <GiMetronome style={{transform: "scaleX(-1)"}} />
                  </div>  
                )}

                <ul className="slid-list">
                  {
                    activeSlides
                      .map((slide ) => (
                        <li className={slide.id === counter ? 'slide active' : 'slide'} key={slide.id} style={{backgroundColor: slide.color}}>

                          { slide.id === counter && (
                            <p>{slide.title}</p>
                          )}
                          
                        </li>
                      ))
                  }
                </ul>
            </div>
          }

        </article>
      }
    </StyledPlayerSettings>
  )
}


Credits